﻿Imports System.Configuration
Imports Microsoft.VisualStudio.TestTools.UnitTesting
Imports System.Reflection
Imports System.Text

Public Class ParticaoEquivalencia

    Private _connectionString As String

    Private _fabrica As FabricaADONet

    Public Sub New(ByVal _connectionName As String)

        If ConfigurationManager.ConnectionStrings(_connectionName) Is Nothing Then
            'Throw New ParticaoEquivalenciaException("A connection string " & _connectionName & " não foi encontrada no arquivo de configuração da aplicação.")
            Throw New ConexaoNaoExisteException()
        End If

        '_connectionString = ConfigurationManager.ConnectionStrings(_connectionName).ConnectionString
        _fabrica = New FabricaADONet(_connectionName)

    End Sub

    Public Function LongArrayFromParticao(ByVal _sql As String, ByVal _qtdItens As Integer) As Long()

        Dim _longs As List(Of Long)
        Dim _long As Long
        Dim _connection As IDbConnection
        Dim _command As IDbCommand
        Dim _dataReader As IDataReader

        _connection = _fabrica.GetConnection
        _command = _fabrica.GetCommand(_sql, _connection)

        _connection.Open()

        Console.WriteLine("--- PARTICAO DE EQUIVALENCIA ----")
        Console.WriteLine(_sql)
        Try
            _dataReader = _command.ExecuteReader()

            _longs = New List(Of Long)

            While _dataReader.Read

                If IsDBNull(_dataReader.GetValue(0)) Then Throw New ParticaoEquivalenciaException("O item " & (_longs.Count + 1) & "º é NULO")
                If Not IsNumeric(_dataReader.GetValue(0)) Then Throw New ParticaoEquivalenciaException("O item " & (_longs.Count + 1) & "º é NÃO É NUMÉRICO")

                _long = CLng(_dataReader.GetValue(0))
                _longs.Add(_long)
                Console.Write(" Long: " & _long)

                If _qtdItens = _longs.Count Then
                    Exit While
                End If

            End While
            Console.WriteLine("")

            If _longs.Count = 0 Then
                Assert.Inconclusive("A partição de equivalência não existe!")
                Return Nothing
                'Throw New ParticaoInexistenteException("A partição de equivalência não existe!")
            End If

        Finally
            If _connection IsNot Nothing AndAlso _connection.State <> ConnectionState.Closed Then
                _connection.Close()
                Console.WriteLine("Conexao da particao fechada")
            End If
        End Try

        Return _longs.ToArray

    End Function


    Public Sub PopularFromQuery(ByVal _sql As String, ByVal _type As System.Type, ByRef _saida As Array)

        Dim _strings As List(Of String)
        Dim _connection As IDbConnection
        Dim _command As IDbCommand
        Dim _dataReader As IDataReader
        Dim generator As New Random
        Dim randomValue As Integer
        Dim _contador As Integer = 0
        Dim _log As String = "" '-- mensagem de log
        Dim _classeFinal As New StringBuilder

        Dim _todasAsColunas As New Dictionary(Of String, String)
        Dim _todosOsFields As New Dictionary(Of String, String)

        randomValue = generator.Next(0, 100)

        _connection = _fabrica.GetConnection
        _command = _fabrica.GetCommand(_sql, _connection)

        _connection.Open()

        Console.WriteLine("--- PARTICAO DE EQUIVALENCIA ----")
        Console.WriteLine(_sql)

        _dataReader = _command.ExecuteReader()

        Dim _fields() As FieldInfo = _type.GetFields()
        For Each _field In _fields
            _todosOsFields.Add(_field.Name, _field.FieldType.Name)
        Next

        Dim _campos(_dataReader.FieldCount - 1) As String

        'Console.WriteLine("'" & Replace(_sql, vbCrLf, " "))
        'Console.WriteLine("Public Class MOCK")
        _classeFinal.Append(vbCrLf & vbCrLf & "'" & Replace(_sql, vbCrLf, " "))
        _classeFinal.Append(vbCrLf & "Public Class MOCK")
        If _dataReader.Read Then

            For i = 0 To (_dataReader.FieldCount - 1)
                _classeFinal.Append(vbCrLf & "Public " & _dataReader.GetName(i) & " as " & _dataReader(i).GetType.Name)
                'Console.WriteLine("Public " & _dataReader.GetName(i) & " as " & _dataReader(i).GetType.Name)
                ''Console.WriteLine("Private _" & _dataReader.GetName(i) & " as String ' " & _dataReader(i).GetType.Name)
                ''Console.WriteLine("Public ReadOnly Property " & _dataReader.GetName(i) & "() As String")
                ''Console.WriteLine(" Get")
                ''Console.WriteLine("     Return _" & _dataReader.GetName(i))
                ''Console.WriteLine(" End Get")
                ''Console.WriteLine("")
            Next
            _classeFinal.Append(vbCrLf & "End Class")


            For i = 0 To (_dataReader.FieldCount - 1)
                _todasAsColunas.Add(_dataReader.GetName(i), _dataReader(i).GetType.Name)
            Next


            For Each _coluna In _todasAsColunas.Keys
                If Not _todosOsFields.ContainsKey(_coluna) Then
                    Throw New ParticaoEquivalenciaException("Não foi possível localizar no " & _type.Name & " o field " & _coluna & ". A classe final deveria ser: " & _classeFinal.ToString)
                End If

                If _todosOsFields(_coluna) <> _todasAsColunas(_coluna) Then
                    Throw New ParticaoEquivalenciaException("Para o " & _type.Name & "." & _coluna & " o tipo correto deveria ser " & _todasAsColunas(_coluna) & ". A classe final deveria ser: " & _classeFinal.ToString)
                End If
            Next

            For Each _coluna In _todosOsFields.Keys
                If Not _todasAsColunas.ContainsKey(_coluna) Then
                    Throw New ParticaoEquivalenciaException("Não foi possível localizar no " & _type.Name & " o field " & _coluna & ". A classe final deveria ser: " & _classeFinal.ToString)
                End If

                If _todasAsColunas(_coluna) <> _todasAsColunas(_coluna) Then
                    Throw New ParticaoEquivalenciaException("Para o " & _type.Name & "." & _coluna & " o tipo correto deveria ser " & _todasAsColunas(_coluna) & ". A classe final deveria ser: " & _classeFinal.ToString)
                End If
            Next

            'Console.WriteLine("End Class")
        Else
            Throw New ParticaoInexistenteException("Não existe partição de equivalência")
        End If

        _dataReader.Close()
        _dataReader = _command.ExecuteReader()

        Dim _listOf As New List(Of Object)
        Dim _tamanhoArray As Integer = 0

        While _dataReader.Read
            Dim _objeto As Object
            Dim _fieldsAutomatic As FieldInfo() = _type.GetFields()
            _objeto = Activator.CreateInstance(_type)
            For Each _field In _fieldsAutomatic
                _field.SetValue(_objeto, _dataReader(_field.Name))
            Next
            _tamanhoArray += 1
            _listOf.Add(_objeto)
            '_saida.Add(_objeto)
        End While

        _saida = Array.CreateInstance(_type, _tamanhoArray)

        For i = 0 To (_listOf.Count - 1)
            _saida(i) = _listOf(i)
        Next

    End Sub

    

    Public Function StringArrayFromQuery(ByVal _sql As String, ByVal ParamArray _colunas() As String) As String()

        Dim _strings As List(Of String)
        Dim _connection As IDbConnection
        Dim _command As IDbCommand
        Dim _dataReader As IDataReader
        Dim generator As New Random
        Dim randomValue As Integer
        Dim _contador As Integer = 0
        Dim _log As String = "" '-- mensagem de log
        randomValue = generator.Next(0, 100)

        _connection = _fabrica.GetConnection
        _command = _fabrica.GetCommand(_sql, _connection)

        _connection.Open()

        Console.WriteLine("--- PARTICAO DE EQUIVALENCIA ----")
        Console.WriteLine(_sql)
        Try

            _dataReader = _command.ExecuteReader()

            _strings = New List(Of String)

            While _dataReader.Read()

                _strings.Clear()
                _log = ""

                Dim _campos(_dataReader.FieldCount - 1) As String
                For i = 0 To (_dataReader.FieldCount - 1)
                    _campos(i) = Ucase(_dataReader.GetName(i))
                Next


                For Each _coluna In _colunas
                    Dim _string As String
                    If Not _campos.Contains(UCase(_coluna)) Then
                        Throw New ParticaoEquivalenciaException("A coluna " & _coluna & " não foi encontrada na query fornecida")
                    End If
                    If IsDBNull(_dataReader(_coluna)) Then
                        _string = Nothing
                    Else
                        _string = _dataReader(_coluna)
                    End If

                    _log &= String.Format("{0} : {1} | ", _coluna, _string)

                    _strings.Add(_string)

                Next

                If _contador = randomValue Then
                    Exit While
                End If
                _contador += 1
            End While

            Console.WriteLine(_log)

            If _strings.Count = 0 Then
                Assert.Inconclusive("A partição de equivalência não existe!")
                Return Nothing
            End If

            'If _dataReader.Read Then

            '    _strings = New List(Of String)

            '    Dim _campos(_dataReader.FieldCount - 1) As String
            '    For i = 0 To (_dataReader.FieldCount - 1)
            '        _campos(i) = _dataReader.GetName(i)
            '    Next


            '    For Each _coluna In _colunas
            '        Dim _string As String
            '        If Not _campos.Contains(_coluna) Then
            '            Throw New ParticaoEquivalenciaException("A coluna " & _coluna & " não foi encontrada na query fornecida")
            '        End If
            '        If IsDBNull(_dataReader(_coluna)) Then
            '            _string = Nothing
            '        Else
            '            _string = _dataReader(_coluna)
            '        End If

            '        Console.Write("{0} : {1} | ", _coluna, _string)

            '        _strings.Add(_string)

            '    Next

            '    Console.WriteLine()

            'Else
            '    Assert.Inconclusive("A partição de equivalência não existe!")
            '    Return Nothing
            '    'Throw New ParticaoInexistenteException("A partição de equivalência não existe!")
            'End If

        Finally
            If _connection IsNot Nothing AndAlso _connection.State <> ConnectionState.Closed Then
                _connection.Close()
                Console.WriteLine("Conexao da particao fechada")
            End If
        End Try

        Return _strings.ToArray

    End Function

    Public Function StringArrayFromQuery(ByVal _sql As String, ByVal _qtdColunas As Integer) As String()

        Dim _strings As List(Of String)
        Dim _connection As IDbConnection
        Dim _command As IDbCommand
        Dim _dataReader As IDataReader
        Dim generator As New Random
        Dim randomValue As Integer
        Dim _contador As Integer = 0
        randomValue = generator.Next(0, 100)

        _connection = _fabrica.GetConnection
        _command = _fabrica.GetCommand(_sql, _connection)

        _connection.Open()

        Console.WriteLine("--- PARTICAO DE EQUIVALENCIA ----")
        Console.WriteLine(_sql)
        Try

            _dataReader = _command.ExecuteReader()

            _strings = New List(Of String)

            While _dataReader.Read()

                _strings.Clear()
                For i = 0 To (_qtdColunas - 1)
                    Dim _str As String

                    If IsDBNull(_dataReader.GetValue(i)) Then
                        _str = String.Empty
                    Else
                        _str = _dataReader.GetValue(i).ToString
                    End If
                    _strings.Add(_str)
                    'Console.Write(" """ & _str & """ | ")
                Next

                If _contador = randomValue Then
                    Exit While
                End If
                _contador += 1

            End While

            For Each _str In _strings
                Console.Write(" """ & _str & """ | ")
            Next
            Console.WriteLine()

            If _strings.Count = 0 Then
                Assert.Inconclusive("A partição de equivalência não existe!")
                Return Nothing
            End If

            'If _dataReader.Read Then

            '    _strings = New List(Of String)

            '    For i = 0 To (_qtdColunas - 1)
            '        Dim _str As String

            '        If IsDBNull(_dataReader.GetValue(i)) Then
            '            _str = String.Empty
            '        Else
            '            _str = _dataReader.GetValue(i).ToString
            '        End If
            '        _strings.Add(_str)
            '        Console.Write(" """ & _str & """ | ")
            '    Next
            '    Console.WriteLine()

            'Else
            '    Assert.Inconclusive("A partição de equivalência não existe!")
            '    Return Nothing
            '    'Throw New ParticaoInexistenteException("A partição de equivalência não existe!")
            'End If


        Finally
            If _connection IsNot Nothing AndAlso _connection.State <> ConnectionState.Closed Then
                _connection.Close()
                Console.WriteLine("Conexao da particao fechada")
            End If
        End Try

        Return _strings.ToArray

    End Function

    Public Function DateFromQuery(ByVal _sql As String, ByVal _column As String) As DateTime
        Dim _date As DateTime
        Dim _connection As IDbConnection
        Dim _command As IDbCommand
        Dim _dataReader As IDataReader

        _connection = _fabrica.GetConnection
        _command = _fabrica.GetCommand(_sql, _connection)

        _connection.Open()

        Console.WriteLine("--- PARTICAO DE EQUIVALENCIA ----")
        Console.WriteLine(_sql)
        Console.WriteLine("--- PARTICAO DE EQUIVALENCIA ----")
        Try

            _dataReader = _command.ExecuteReader()

            If _dataReader.Read Then


                Dim _campos(_dataReader.FieldCount - 1) As String
                For i = 0 To (_dataReader.FieldCount - 1)
                    _campos(i) = _dataReader.GetName(i)
                Next

                If Not _campos.Contains(_column) Then
                    Throw New ParticaoEquivalenciaException("A coluna " & _column & " não foi encontrada na query fornecida")
                End If

                If IsDBNull(_dataReader(_column)) Then Throw New ParticaoEquivalenciaException("O primeiro valor da query é NULO")
                If Not IsDate(_dataReader(_column)) Then Throw New ParticaoEquivalenciaException("O primeiro valor da coluna " & _column & " não é date")

                _date = CDate(_dataReader(_column))
                Console.WriteLine("Date = " & _date.ToLongDateString)
            Else
                Assert.Inconclusive("A partição de equivalência não existe!")
                Return Nothing
                'Throw New ParticaoInexistenteException("A partição de equivalência não existe!")
            End If


        Finally
            If _connection IsNot Nothing AndAlso _connection.State <> ConnectionState.Closed Then
                _connection.Close()
                Console.WriteLine("Conexao da particao fechada")
            End If
        End Try

        Return _date
    End Function


    Private _particoesManuais As IDictionary(Of String, String())

    Public Sub ParticaoManualStringSet(ByVal _nomeDaParticao As String, ByVal _strings() As String)

        If Me._particoesManuais Is Nothing Then Me._particoesManuais = New Dictionary(Of String, String())

        If Me._particoesManuais.ContainsKey(_nomeDaParticao) Then
            Throw New ParticaoEquivalenciaException("A partição manual " & _nomeDaParticao & " já existe!")
        End If
        Me._particoesManuais.Add(_nomeDaParticao, _strings)

    End Sub

    Public Function ParticaoManualStringGet(ByVal _nomeDaParticao As String) As String

        Dim _array As String()
        Dim _tamanhoArray As Integer
        Dim generator As New Random
        Dim randomValue As Integer

        Randomize()
        If _particoesManuais Is Nothing OrElse Not _particoesManuais.ContainsKey(_nomeDaParticao) Then
            Throw New ParticaoEquivalenciaException("A partição manual " & _nomeDaParticao & " não existe, portanto não pode ser recuperada!")
        End If

        _array = Me._particoesManuais(_nomeDaParticao)
        _tamanhoArray = (_array.Count - 1)
        randomValue = generator.Next(0, _tamanhoArray)
        Threading.Thread.Sleep(3)
        Return _array(randomValue)

    End Function


    Public Function LongFromQuery(ByVal _sql As String) As Long

        Dim _long As Nullable(Of Long)
        Dim _connection As IDbConnection
        Dim _command As IDbCommand
        Dim _dataReader As IDataReader
        Dim generator As New Random
        Dim randomValue As Integer
        Dim _contador As Integer = 0
        randomValue = generator.Next(0, 100)

        _connection = _fabrica.GetConnection
        _command = _fabrica.GetCommand(_sql, _connection)

        _connection.Open()

        Console.WriteLine("--- PARTICAO DE EQUIVALENCIA ----")
        Console.WriteLine(_sql)
        Console.WriteLine("--- PARTICAO DE EQUIVALENCIA ----")
        Try

            _dataReader = _command.ExecuteReader()

            '--
            While _dataReader.Read()

                If IsDBNull(_dataReader.GetValue(0)) Then Throw New ParticaoEquivalenciaException("O primeiro valor da query é NULO")
                If Not IsNumeric(_dataReader.GetValue(0)) Then Throw New ParticaoEquivalenciaException("O primeiro valor da query não é númerico")

                _long = CLng(_dataReader.GetValue(0))
                'Console.WriteLine("Long = " & _long)

                If _contador = randomValue Then
                    Exit While
                End If
                _contador += 1

            End While


            If Not _long.HasValue Then
                Assert.Inconclusive("A partição de equivalência não existe!")
                Return Nothing
            End If

            Console.WriteLine("Long = " & _long)
            '--

            'If _dataReader.Read Then

            '    If IsDBNull(_dataReader.GetValue(0)) Then Throw New ParticaoEquivalenciaException("O primeiro valor da query é NULO")
            '    If Not IsNumeric(_dataReader.GetValue(0)) Then Throw New ParticaoEquivalenciaException("O primeiro valor da query não é númerico")

            '    _long = CLng(_dataReader.GetValue(0))
            '    Console.WriteLine("Long = " & _long)
            'Else
            '    Assert.Inconclusive("A partição de equivalência não existe!")
            '    Return Nothing
            '    'Throw New ParticaoInexistenteException("A partição de equivalência não existe!")
            'End If


        Finally
            If _connection IsNot Nothing AndAlso _connection.State <> ConnectionState.Closed Then
                _connection.Close()
                Console.WriteLine("Conexao da particao fechada")
            End If
        End Try

        Return _long

    End Function

    Public Function StringFromQuery(ByVal _sql As String) As String

        Dim _string As String
        Dim _connection As IDbConnection
        Dim _command As IDbCommand
        Dim _dataReader As IDataReader

        _connection = _fabrica.GetConnection
        _command = _fabrica.GetCommand(_sql, _connection)

        _connection.Open()

        Console.WriteLine("--- PARTICAO DE EQUIVALENCIA ----")
        Console.WriteLine(_sql)
        Try

            _dataReader = _command.ExecuteReader()

            If _dataReader.Read Then

                If IsDBNull(_dataReader.GetValue(0)) Then Throw New ParticaoEquivalenciaException("O primeiro valor da query é NULO")

                _string = _dataReader.GetValue(0).ToString
                Console.WriteLine(" String = """ & _string & """ | ")
            Else
                Assert.Inconclusive("A partição de equivalência não existe!")
                Return Nothing
                'Throw New ParticaoInexistenteException("A partição de equivalência não existe!")
            End If

        Finally
            If _connection IsNot Nothing AndAlso _connection.State <> ConnectionState.Closed Then
                _connection.Close()
                Console.WriteLine("Conexao da particao fechada")
            End If
        End Try

        Return _string

    End Function

    'Public Function StringFromQuery(ByVal _sql As String) As String

    '    Dim _string As String
    '    Dim _connection As IDbConnection = New SqlClient.SqlConnection
    '    Dim _command As IDbCommand = New SqlClient.SqlCommand
    '    Dim _dataReader As IDataReader

    '    _connection.ConnectionString = _connectionString
    '    _command.Connection = _connection
    '    _command.CommandText = _sql

    '    _connection.Open()

    '    Console.WriteLine("--- PARTICAO DE EQUIVALENCIA ----")
    '    Console.WriteLine(_sql)
    '    Console.WriteLine("--- PARTICAO DE EQUIVALENCIA ----")
    '    Try
    '        _dataReader = _command.ExecuteReader()

    '        'If _dataReader.FieldCount = 0 then Throw
    '        'If _dataReader.RecordsAffected > 0 then Throw

    '        If _dataReader.Read Then

    '            'If IsDBNull( _dataReader.GetValue(0)) then Throw
    '            'If String.IsNullOrEmpty( _dataReader.GetValue(0)) then Throw 

    '            _string = _dataReader.GetValue(0)
    '        Else
    '            Throw New ParticaoInexistenteException("A partição de equivalência não existe!")
    '        End If


    '    Finally
    '        If _connection IsNot Nothing AndAlso _connection.State <> ConnectionState.Closed Then
    '            _connection.Close()
    '            Console.WriteLine("Conexao da particao fechada")
    '        End If
    '    End Try

    '    Return _string

    'End Function

End Class
